﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.IO;

using FbHelperWP7NonUi.TextHelpers;
using System.IO.IsolatedStorage;

namespace FbHelperWP7NonUi.BookStorage.PhoneStorage
{
    public sealed class PhoneDirectory
    {
        private const string bookPath = "Books";

        private static readonly PhoneDirectory root = new PhoneDirectory( bookPath, null );

        private readonly string directoryPath;
        private readonly string directoryName;
        private readonly PhoneDirectory parent;

        private PhoneDirectory( string directoryName, PhoneDirectory parent )
        {
            this.directoryName = directoryName;
            this.parent = parent;

            if (parent == null)//for root directory
            {
                directoryPath = bookPath;

                using (IsolatedStorageFile isolatedStorage = OpenIsolatedStorage())
                {
                    if (!isolatedStorage.DirectoryExists( bookPath ))
                    {
                        FillDefaultDirectory();
                    }
                }

                return;
            }

            directoryPath = Path.Combine( parent.directoryPath, directoryName );
        }

        public PhoneDirectory Parent
        {
            get
            {
                return parent;
            }
        }

        public string Name
        {
            get
            {
                return directoryName;
            }
        }

        public PhoneDirectory OpenDirectory( string name )
        {
            string newDirPath = Path.Combine( directoryPath, name );

            using (IsolatedStorageFile isolatedStorage = OpenIsolatedStorage())
            {
                if (!isolatedStorage.DirectoryExists( newDirPath ))
                    throw new Exception( String.Format( "Directory {0} hasn`t existed", name ) );
            }

            return new PhoneDirectory( name, this );
        }

        public List<string> GetSubdirectories()
        {
            int directoryPreffixLenght = directoryPath.Length;
            using (IsolatedStorageFile isolatedStorage = OpenIsolatedStorage())
            {
                return isolatedStorage.GetDirectoryNames( directoryPath + "/*" )
                    .Where( dirName => !dirName.Contains( '/' ) && !dirName.Contains( '\\' ) ).ToList();
            }
        }

        public List<string> GetFiles()
        {
            int directoryPreffixLenght = directoryPath.Length;

            using (IsolatedStorageFile isolatedStorage = OpenIsolatedStorage())
            {
                return isolatedStorage.GetFileNames( directoryPath + "/*" )
                                .Where( dirName => !dirName.Contains( '/' ) && !dirName.Contains( '\\' ) )
                                .ToList();
            }
        }

        public void AddFile( string fileName, byte[] fileEntry )
        {
            string filePath = Path.Combine( directoryPath, fileName );

            using (IsolatedStorageFile isolatedStorage = OpenIsolatedStorage())
            {
                if (isolatedStorage.FileExists( filePath ))
                    throw new Exception( String.Format( "File {0} has already existed", fileName ) );

                using (Stream outStream = isolatedStorage.CreateFile( filePath ))
                {
                    outStream.Write( fileEntry, 0, fileEntry.Length );
                    
                    outStream.Close();
                }
            }
        }

        public void AddDirectory( string name )
        {
            string newDirPath = Path.Combine( directoryPath, name );

            using (IsolatedStorageFile isolatedStorage = OpenIsolatedStorage())
            {
                if (isolatedStorage.DirectoryExists( newDirPath ))
                    throw new Exception( String.Format( "Directory {0} has already existed", name ) );

                isolatedStorage.CreateDirectory( newDirPath );
            }
        }

        public void RemoveFile( string fileName )
        {
            string filePath = Path.Combine( directoryPath, fileName );

            using (IsolatedStorageFile isolatedStorage = OpenIsolatedStorage())
            {
                if (isolatedStorage.FileExists( filePath ))
                    isolatedStorage.DeleteFile( filePath );
            }
        }

        public void RemoveDirectory( string name )
        {
            string dirPath = Path.Combine( directoryPath, name );

            using (IsolatedStorageFile isolatedStorage = OpenIsolatedStorage())
            {
                if (isolatedStorage.DirectoryExists( dirPath ))
                    isolatedStorage.DeleteDirectory( dirPath );
            }
        }

        public override int GetHashCode()
        {
            return Name.GetHashCode();
        }

        public override bool Equals( object obj )
        {
            PhoneDirectory another = obj as PhoneDirectory;

            if (another == null)
                return false;

            if (another.Name != this.Name)
                return false;

            if (another.Parent == null && this.Parent == null)
                return true;

            if (another.Parent == null || this.Parent == null)
                return false;

            return another.Parent.Equals( this.Parent );
        }

        private void FillDefaultDirectory()
        {
            using (IsolatedStorageFile isolatedStorage = OpenIsolatedStorage())
            {
                isolatedStorage.CreateDirectory( bookPath );
            }

            AddFile( BookResources.PohititelyDush3, BookResources.PohititelyDush3File );
        }

        public Book OpenFile( string fileName )
        {
            string filePath = Path.Combine( directoryPath, fileName );

            using (IsolatedStorageFile isolatedStorage = OpenIsolatedStorage())
            {
                using (Stream inStream = isolatedStorage.OpenFile( filePath, FileMode.Open ))
                {
                    switch (Path.GetExtension( fileName ).ToUpperInvariant())
                    {
                        case ".FB2":
                            return Fb2Book.Open( inStream );

                        case ".TXT":
                            return TextBook.Open( inStream );

                        default:
                            throw new NotSupportedException( String.Format( "Type of file {0} is not supported", fileName ) );
                    }
                }
            }
        }

        public static PhoneDirectory Root
        {
            get
            {
                return root;
            }
        }

        private static IsolatedStorageFile OpenIsolatedStorage()
        {
#if WINDOWS_PHONE
            return IsolatedStorageFile.GetUserStoreForApplication();
#else
            return IsolatedStorageFile.GetUserStoreForDomain();
#endif
        }


    }
}
